import 'package:ai_report/data/tile_ext.dart';
import 'package:ai_report/special_dot.dart';
import 'package:ai_report/util/tool.dart';
import 'package:tile/tile.dart';

import 'data/terms_coordinates.dart';
import 'direction.dart';
import 'util/print.dart';

/// 术语2.0
enum Terms {
  NONE(''),
  CHESS('棋'),
  KO('劫'),
  CAPTURE('提子'),
  CAPTURE_KO('提劫'),
  MULTI_STRIKE_PAYBACK('打多还一'),
  SACRIFICE('扑'),
  ATARI('打吃'),
  DOUBLE_ATARI('双打'),
  MAKE_EYE('做眼'),
  MAKE_KO('做劫'),
  CROWD('挤'),
  CUT('断'),
  STICK('粘'),
  GROUP('团'),
  DIG('挖'),
  CRUSH('冲'),
  TIGER('虎'),
  DOUBLE_TIGER('双虎'),
  SMALL_JUMP('小跳'),
  DOT('点'),
  DOT_ONE_ONE('点(一一)'),
  KOSUMI('尖'),
  HANE('扳'),
  TURN('拐'),
  RESIST('挡'),
  KOSUMI_TOP('尖顶'),
  KOSUMI_ZUKE('尖刺'),
  POKE('碰'),
  SHOULDER_HIT('肩冲'),
  BLOCK('拦'),
  STRETCH('并'),
  SMALL_FLY('小飞'),
  ELEPHANT_STEP('象步'),
  JUMP('跳'),
  LARGE_JUMP('大跳'),
  BIG_FLY('大飞'),
  SUPER_BIG_JUMP('超大跳'),
  SUPER_BIG_FLY('超大飞'),
  PEEP('尖刺'),
  WEDGE('尖穿'),
  THRUST('刺'),
  BREAK_ELEPHANT_EYE('穿象眼'),
  DIAGONAL_CONNECT('尖连'),
  TOP('顶'),
  PRESS('压'),
  CLIMB('爬'),
  DEPEND('靠'),
  HOLD('托'),
  ATTACH('贴'),
  BREAK_ONE('拆一'),
  ONE_ONE_ENTER('一一塞入'),
  TWO_TWO_HOLD('二二托'),
  THREE_THREE_HOLD('三三托'),
  STAR_DEPEND('星位靠'),
  MOYO_SHIMARI('无忧角'),
  SMALL_EYE_ENCLOSURE('小目守角'),
  SMALL_EYE_DG_ENCLOSURE('小目单关守角'),
  SMALL_FLY_ENCLOSURE('小飞守角'),
  STAR_ENCLOSURE('星位守角'),
  STAR_DG_ENCLOSURE('星位单关守角'),
  BIG_JUMP_ENCLOSURE('大跳守角'),
  STAR_BIG_JUMP_ENCLOSURE('星位大跳守角'),
  STAR_BREAK_TWO_ENCLOSURE('星位拆⼆守⻆'),
  BREAK_TWO('拆⼆'),
  BIG_FLY_ENCLOSURE('大飞守角'),
  THREE_THREE_INVASION('三三挂'),
  SMALL_EYE_HIGH_INVASION('⼩⽬⾼挂'),
  SMALL_EYE_INVASION_CORNER('⼩⽬挂⻆'),
  STAR_HIGH_INVASION('星位⾼挂'),
  STAR_INVASION_CORNER('星位挂⻆'),
  SUPPRESS('镇'),
  LEAK('漏'),
  INTERCEPT('栏'),
  PREVENT_CROSS('阻渡'),
  DISCONNECT('断开'),
  BACK_TIGER('倒虎'),
  TIGER_THORN('虎刺');

  final String desc;

  const Terms(this.desc);
}

/// 将术语赋值给board.currNode.c
String termsInfo(Board board) {
  // if (board.currNode.c.isEmpty) {
  //   board.currNode.c = chessDescription(board);
  // }
  // return board.currNode.c;
  return chessDescription(board);
}

/// 当前手的围棋术语
/// 优先级:劫、打几还一 > 提子 > 扑 > 打吃 > 断 >做劫、做眼 > 粘（接） > 团 > 挤 > 紧贴术语 > 斜斜术语 > 复合术语 > 并列术语 > 方位抽象术语
String chessDescription(Board board, {int type = 0}) {
  if (board.getCount() == 0) {
    return Terms.CHESS.desc;
  }
  if (type == 0) {
    if (board.isLast) {
      return Terms.CHESS.desc;
    }
  }
  if (board.lastOrderedStep == null) {
    return Terms.CHESS.desc;
  }
  if (board.lastOrderedStep!.isPass) {
    return '(pass)';
  }
  String steps = board.allStep;
  int boardSize = board.getBoardSize();
  ChessStep? nextStep =
      type == 0 ? board.nextOrderedStep! : board.lastOrderedStep!;
  Terms terms = Terms.CHESS;
  Board tempBoard = Board(boardSize);
  if (type == 1) {
    steps = steps.substring(0, steps.length - 5);
  }

  tempBoard.showYzSteps(steps);

  tempBoard.showXY(nextStep.x, nextStep.y);
  var lastStep = tempBoard.lastOrderedStep;

  if (lastStep!.isPass) {
    return '(pass)';
  }
  int airCount = tempBoard.airCount(lastStep);
  if (lastStep.deadList.isNotEmpty) {
    int deadCount = lastStep.deadList.length;
    if (deadCount == 1) {
      /// 提完子,自己只有1口气了,认为是劫
      if (airCount == 1) {
        terms = Terms.KO;
      } else {
        terms = Terms.CAPTURE; // 存⼊基础术语盒⼦
        /// 同时满足提、做劫：提劫
        if (isMakeEye(board, nextStep) && airCount == 1) {
          terms = Terms.CAPTURE_KO;
        } else {
          return '提$deadCount子';
        }
      }
    } else {
      /// 打几还一
      if (airCount == 1) {
        if (deadCount >= 4) {
          terms = Terms.MULTI_STRIKE_PAYBACK;
        } else {
          return '打${numberToChinese(deadCount)}还一';
        }
      } else {
        terms = Terms.CAPTURE;
      }
    }
  } else {
    /// 打吃
    bool isDc = false;
    int dcCount = 0;
    var nearList = nearChess(tempBoard, nextStep);
    for (var it in nearList) {
      if (tempBoard.airCount(it) == 1) {
        dcCount++;
        isDc = true;
      }
    }
    if (isDc) {
      // 双打
      if (dcCount >= 2) {
        terms = Terms.DOUBLE_ATARI;
      } else {
        // 扑
        if (airCount == 1) {
          terms = Terms.SACRIFICE;
        } else {
          // 打吃,存⼊基础术语盒⼦
          terms = Terms.ATARI;
        }
      }
    } else {
      if (isBreak(tempBoard, nextStep)) {
        // 断
        terms = Terms.CUT;
      } else if (isMakeEye(board, nextStep)) {
        if (airCount == 1) {
          // 做劫
          terms = Terms.MAKE_KO;
        } else {
          terms = Terms.MAKE_EYE;
        }
      } else {
        // 虎
        // 先判断双虎
        if (isDoubleTiger(board, nextStep)) {
          terms = Terms.DOUBLE_TIGER;
        } else if (isBreak(tempBoard, nextStep, type: 1)) {
          terms = Terms.STICK;
        } else if (isBreak(tempBoard, nextStep, type: 2)) {
          terms = Terms.GROUP;
        } else {
          if (isCrowd(board, nextStep)) {
            terms = Terms.CROWD;
          } else {
            terms = descFromCoordinates(tempBoard, nextStep);
            if (terms == Terms.NONE) {
              terms = Terms.CHESS;
            }
          }
        }
      }
    }
  }
  printInfo('最终得到的围棋术语:${terms.desc}');
  return terms.desc;
}

/// 双虎
bool isDoubleTiger(Board board, ChessStep chessStep) {
  printInfo('进入双虎的判断');
  if (chessStep.x == 0 || chessStep.y == 0) {
    return false;
  }
  int x = chessStep.x.toInt();
  int y = chessStep.y.toInt();
  int bw = chessStep.bw;
  int chessBw(int dx, int dy) {
    if (x + dx <= 0 || y + dy <= 0) {
      return -1;
    }
    if (x + dx >= 20 || y + dy >= 20) {
      return -1;
    }
    return board.getChessValue(x + dx, y + dy);
  }

  List<List<int>> directions = [
    [-1, -1], // 0左上
    [-2, 0], // 2上2
    [-1, 1], // 3右上
    [1, -1], // 4左下
    [0, -2], // 6左2
    [2, 0], // 8下2
    [1, 1], // 9右下
    [0, 2], // 11右2
  ];

  bool check(int i1, int i2, int i3) {
    var bw1 = chessBw(directions[i1][0], directions[i1][1]);
    var bw2 = chessBw(directions[i2][0], directions[i2][1]);
    var bw3 = chessBw(directions[i3][0], directions[i3][1]);

    print('bw:$bw');
    print('bw1:$bw1,bw2:$bw2,bw3:$bw3');

    return bw1 == bw && bw2 == bw && bw3 == bw;
  }

  return check(1, 2, 7) || check(4, 3, 5) || check(5, 6, 7) || check(4, 0, 1);
}

/// 上下左右4个位置的棋谱
List<ChessStep> nearChess(Board board, ChessStep chessStep) {
  printInfo('进入打吃、扑的判断');
  int x = chessStep.x.toInt();
  int y = chessStep.y.toInt();
  int bw = chessStep.bw;

  bool isValid(int nx, int ny) {
    if (nx > 0 && ny > 0 && nx <= 19 && ny <= 19) {
      int value = board.getChessValue(nx, ny);
      return value > 0 && value != bw;
    }
    return false;
  }

  List<List<int>> directions = [
    [0, -1],
    [0, 1],
    [-1, 0],
    [1, 0]
  ];

  return directions
      .map((d) => ChessStep(x + d[0], y + d[1], 3 - bw))
      .where((step) => isValid(step.x, step.y))
      .toList();
}

/// 做眼
bool isMakeEye(Board board, ChessStep chessStep) {
  printInfo('进入做眼和做劫的判断');
  if (chessStep.x == 0 || chessStep.y == 0) {
    return false;
  }
  int x = chessStep.x.toInt();
  int y = chessStep.y.toInt();
  int bw = chessStep.bw;
  int chessBw(int dx, int dy) {
    if (x + dx <= 0 || y + dy <= 0) {
      return -1;
    }
    if (x + dx >= 20 || y + dy >= 20) {
      return -1;
    }
    return board.getChessValue(x + dx, y + dy);
  }

  List<List<int>> directions = [
    [-1, -1], // 0左上
    [-1, 0], // 1上1
    [-2, 0], // 2上2
    [-1, 1], // 3右上
    [1, -1], // 4左下
    [0, -1], // 5左1
    [0, -2], // 6左2
    [1, 0], // 7下1
    [2, 0], // 8下2
    [1, 1], // 9右下
    [0, 1], // 10右1
    [0, 2], // 11右2
  ];

  bool check(int i1, int i2, int i3, i4) {
    var bw1 = chessBw(directions[i1][0], directions[i1][1]);
    var bw2 = chessBw(directions[i2][0], directions[i2][1]);
    var bw3 = chessBw(directions[i3][0], directions[i3][1]);
    var bw4 = chessBw(directions[i4][0], directions[i4][1]);

    if (bw3 == -1) {
      if (bw1 == -1) {
        return bw4 == bw && bw2 == 0;
      } else if (bw4 == -1) {
        return bw1 == bw && bw2 == 0;
      } else {
        return bw1 == bw && bw2 == 0 && bw4 == bw;
      }
    } else {
      if (bw1 == -1) {
        return bw2 == 0 && bw3 == bw && bw4 == bw;
      }

      if (bw4 == -1) {
        return bw1 == bw && bw2 == 0 && bw3 == bw;
      }
    }

    return bw1 == bw && bw2 == 0 && bw3 == bw && bw4 == bw;
  }

  return check(0, 1, 2, 3) ||
      check(4, 5, 6, 0) ||
      check(9, 7, 8, 4) ||
      check(3, 10, 11, 9);
}

/// type: 0-断、1-粘、2-团
bool isBreak(Board board, ChessStep chessStep, {int type = 0}) {
  printInfo('进入断、粘和团的判断');
  if (chessStep.x == 0 ||
      chessStep.y == 0 ||
      chessStep.x == 19 ||
      chessStep.y == 19) {
    return false;
  }
  int x = chessStep.x.toInt();
  int y = chessStep.y.toInt();
  int bw = chessStep.bw;

  int chessBw(int dx, int dy) {
    if (x + dx <= 0 || y + dy <= 0) {
      return -1;
    }
    if (x + dx >= 20 || y + dy >= 20) {
      return -1;
    }
    return board.getChessValue(x + dx, y + dy);
  }

  List<List<int>> directions = [
    [-1, -1], // 0左上
    [0, -1], // 1左
    [-1, 0], // 2上
    [1, 1], // 3右下
    [0, 1], // 4右
    [1, 0], // 5下
    [-1, 1], // 6右上
    [1, -1] // 7左下
  ];

  bool check(int i1, int i2, int i3) {
    int bw1 = chessBw(directions[i1][0], directions[i1][1]);
    int bw2 = chessBw(directions[i2][0], directions[i2][1]);
    int bw3 = chessBw(directions[i3][0], directions[i3][1]);

    return bw1 ==
            (type == 0
                ? bw
                : type == 1
                    ? 3 - bw
                    : 0) &&
        bw2 == (type == 0 ? 3 - bw : bw) &&
        bw3 == (type == 0 ? 3 - bw : bw);
  }

  return check(0, 1, 2) || check(6, 4, 2) || check(3, 4, 5) || check(7, 1, 5);
}

/// 挤
bool isCrowd(Board board, ChessStep chessStep) {
  int x = chessStep.x.toInt();
  int y = chessStep.y.toInt();
  int bw = chessStep.bw;

  bool isValid(int nx, int ny) {
    if (nx > 0 && ny > 0 && nx <= 19 && ny <= 19) {
      int value = board.getChessValue(nx, ny);
      return value > 0;
    }
    return false;
  }

  List<List<int>> directions = [
    [0, -1],
    [0, 1],
    [-1, 0],
    [1, 0]
  ];

  List<ChessStep> list = directions
      .map((d) => ChessStep(x + d[0], y + d[1], bw))
      .where((step) => isValid(step.x, step.y))
      .toList();

  var sameCount = 0;
  var differentCount = 0;

  for (var it in list) {
    if (board.getChessValue(it.x, it.y) == bw) {
      sameCount++;
    }

    if (board.getChessValue(it.x, it.y) == 3 - bw) {
      differentCount++;
    }
  }
  // print('list:${list.length}');
  // print('sameCount: $sameCount, differentCount: $differentCount');
  if (list.length == 4) {
    if (sameCount == 1 && differentCount == 3) {
      return true;
    }
  }

  return false;
}

/// 通过坐标系来判断
Terms descFromCoordinates(Board board, ChessStep chessStep) {
  if (chessStep.x == 0 || chessStep.y == 0) {
    return Terms.NONE;
  }

  final int x = chessStep.y;
  final int y = 20 - chessStep.x;

  /// 计算两点之间的距离的平方
  int distanceSquared(int xx, int yy) =>
      (x - xx) * (x - xx) + (y - yy) * (y - yy);

  /// 获取棋盘上所有非空棋子的坐标
  List<ChessStep> getNonZeroChessSteps() {
    final grid = board.getChessBoard();
    List<ChessStep> steps = [];
    for (int i = 0; i < board.getBoardSize(); i++) {
      for (int j = 0; j < board.getBoardSize(); j++) {
        if (grid[i][j] != 0) {
          steps.add(ChessStep(j + 1, 20 - (i + 1), grid[i][j]));
        }
      }
    }
    return steps;
  }

  final nonZeroSteps = getNonZeroChessSteps();

  for (int s = 1; s < 18; s++) {
    int oppositeCount = 0; // 对方棋子数
    int selfCount = 0; // 己方棋子数
    List<ChessStep> selfStepList = [];
    List<ChessStep> oppositeStepList = [];

    for (final step in nonZeroSteps) {
      final distance = distanceSquared(step.x, step.y);
      if (distance == s) {
        if (step.bw != chessStep.bw) {
          oppositeCount++;
          oppositeStepList.add(step);
        } else {
          selfCount++;
          selfStepList.add(step);
        }
      }
    }

    final desc = _getDescription(s, oppositeCount, selfCount,
        selfStepList: selfStepList,
        oppositeStepList: oppositeStepList,
        board: board,
        chessStep: chessStep);
    if (desc != Terms.NONE) {
      return desc;
    }
  }

  return Terms.NONE;
}

Terms _getDescription(int distanceSquared, int oppositeCount, int selfCount,
    {List<ChessStep>? selfStepList,
    List<ChessStep>? oppositeStepList,
    Board? board,
    ChessStep? chessStep}) {
  Terms desc = Terms.NONE;
  var descCoordinates = calculateDirection(chessStep!.toGtp());
  // 紧贴术语判定
  if (distanceSquared == 1) {
    desc = _nearTerms(oppositeCount, selfCount,
        stepList: oppositeStepList,
        board: board,
        chessStep: chessStep,
        descCoordinates: descCoordinates,
        selfStepList: selfStepList);
  }
  // 斜斜术语判定
  else if (distanceSquared == 2) {
    desc = _xxTerms(oppositeCount, selfCount,
        stepList: oppositeStepList,
        selfStepList: selfStepList,
        board: board,
        chessStep: chessStep,
        descCoordinates: descCoordinates);
  }

  if (desc != Terms.NONE) {
    return desc;
  } else {
    return _parataxisTerms(oppositeCount, selfCount, distanceSquared, chessStep,
        board: board,
        selfStepList: selfStepList,
        oppositeStepList: oppositeStepList);
  }
}

// 紧贴术语判定
Terms _nearTerms(int count1, int count4,
    {List<ChessStep>? selfStepList,
    List<ChessStep>? stepList,
    Board? board,
    ChessStep? chessStep,
    TermsCoordinates? descCoordinates}) {
  printInfo('进入紧贴术语判定s1:$count1,s4:$count4');
  int s1 = count1;
  int s4 = count4;
  bool isSymmetry() {
    if (stepList == null) {
      return false;
    }
    return stepList.length >= 2 &&
        (stepList[0].x == stepList[1].x || stepList[0].y == stepList[1].y);
  }

  if (descCoordinates != null) {
    printInfo('棋子的线路：${descCoordinates.line}');
    // 特殊点 ⼀⼀ +2S1
    if (descCoordinates.direction == '一一') {
      s1 = s1 + 2;
      printInfo('修正后的s1:$s1,s4:$s4');
    }
    // ⼀线 +1S1
    else if (descCoordinates.line == '一线') {
      s1 = s1 + 1;
      printInfo('修正后的s1:$s1,s4:$s4');
    }
  }

  if (s1 == 0 && (s4 == 4 || s4 == 3)) {
    return Terms.STICK;
  }

  if ((s1 == 1 && s4 == 3) || (s1 == 3 && s4 == 1)) {
    return Terms.STICK;
  }
  // 3S1 * 1S4
  if (s1 == 3 && s4 == 1) {
    if (descCoordinates!.direction == '一一') {
      return Terms.ONE_ONE_ENTER;
    } else if (descCoordinates.line == '⼀线') {
      return Terms.PREVENT_CROSS; // 到底是阻渡还是断开
    } else {
      return Terms.CROWD;
    }
  }
  switch (s4) {
    case 0:
      if (s1 == 2) {
        if (isSymmetry()) {
          return Terms.DIG;
        } else {
          // 特殊点：一一 走一一、点?
          if (descCoordinates!.direction == '一一') {
            // return Terms.DOT;
            return Terms.DOT_ONE_ONE;
          } else if (descCoordinates.line == '一线') {
            // 进⼊⽅位抽象判定
            return _directionAbstractTerms(s1, s4,
                distanceSquared: 1, nextStep: chessStep);
          } else {
            return Terms.CROWD;
          }
        }
      } else if (s1 == 1) {
        var term = _compositeTerms(board!, chessStep!,
            selfStepList: selfStepList,
            oppositeStepList: stepList,
            distance: 1);
        if (term != Terms.NONE) {
          return term;
        } else {
          // 进入后续判定
        }
      }
      break;
    case 1:
      // 2S1*1S4
      if (s1 == 2) {
        if (isSymmetry()) {
          return Terms.CRUSH;
        } else {
          return Terms.CROWD;
        }
      }
      // 1S1*1S4
      else if (s1 == 1) {
        return _compositeTerms(board!, chessStep!,
            selfStepList: selfStepList,
            oppositeStepList: stepList,
            distance: 1);
      } else if (s1 == 0) {
        return Terms.STRETCH;
      }
      break;
    case 2:
      if (s1 == 0) {
        return Terms.GROUP;
      }
      // 1S1*2S4/2S1*2S4
      else if (s1 == 1 || s1 == 2) {
        // if (_haveChess()) {
        //   return Terms.STICK;
        // } else {
        return Terms.GROUP;
        // }
      }
      break;
  }
  return Terms.NONE;
}

bool _haveChess() {
  return true;
}

// 斜斜术语判定
Terms _xxTerms(int count2, int count5,
    {List<ChessStep>? stepList,
    List<ChessStep>? selfStepList,
    Board? board,
    ChessStep? chessStep,
    TermsCoordinates? descCoordinates}) {
  bool isSymmetry(List<ChessStep> steps) {
    for (var it in steps) {
      printInfo('${it.x},${it.y}');
    }
    return steps.length >= 2 &&
        (steps[0].x == steps[1].x || steps[0].y == steps[1].y);
  }

  int s2 = count2;
  int s5 = count5; // 颜色相同

  printInfo('进入斜斜术语判定s2:$s2,s5:$s5');

  if (descCoordinates != null) {
    // 特殊点 ⼀⼀ +2S1
    if (descCoordinates.direction == '一一') {
      s2 = s2 + 3;
      printInfo('修正后的s2:$s2,s5:$s5');
    }
    // ⼀线 +1S1
    else if (descCoordinates.line == '一线') {
      s2 = s2 + 2;
      printInfo('修正后的s2:$s2,s5:$s5');
    }
  }

  switch (s2) {
    case 0:
      if (s5 == 4) return Terms.CHESS;
      if (s5 == 3) return Terms.DOUBLE_TIGER;
      if (s5 == 2) {
        return isSymmetry(selfStepList!) ? Terms.TIGER : Terms.DIAGONAL_CONNECT;
      }
      // 0S2*1S5
      if (s5 == 1) return Terms.KOSUMI;
      break;
    case 1:
      // 1S2*3S5
      if (s5 == 3) return Terms.DOUBLE_TIGER;
      if (s5 == 2) {
        return isSymmetry(selfStepList!) ? Terms.TIGER : Terms.DIAGONAL_CONNECT;
      }
      // 1S2*1S5
      if (s5 == 1) return Terms.KOSUMI;
      if (s5 == 0) {
        return _compositeTerms(board!, chessStep!,
            selfStepList: selfStepList, oppositeStepList: stepList);
      }
      break;
    case 2:
      // 2S2*2S5
      if (s5 == 2) {
        if (descCoordinates!.line == '一一') {
          return Terms.BACK_TIGER;
        } else {
          return isSymmetry(selfStepList!)
              ? Terms.TIGER_THORN
              : Terms.DIAGONAL_CONNECT;
        }
      }
      // 2S2*1S5
      else if (s5 == 1) {
        if (descCoordinates!.line == '一线') {
          return Terms.KOSUMI;
        } else {
          return isSymmetry(selfStepList!) ? Terms.TIGER_THORN : Terms.WEDGE;
        }
      }
      // 2S2*0S5
      if (s5 == 0) {
        if (descCoordinates!.line == '一线') {
          return Terms.CHESS;
        } else {
          return isSymmetry(stepList!)
              ? Terms.THRUST
              : Terms.BREAK_ELEPHANT_EYE;
        }
      }
      break;
    case 3:
      // 3S2*0S5
      if (s5 == 0) return Terms.DOT;
      // 3S2*1S5
      if (s5 == 1) {
        if (descCoordinates!.direction == '一一') {
          return Terms.DOT;
        } else if (descCoordinates.line == '一线') {
          return Terms.KOSUMI;
        } else {
          return Terms.PEEP;
        }
      }
      break;
    case 4:
      // 4S2*0S5
      if (s5 == 0) return Terms.DOT;
      break;
  }
  return Terms.NONE;
}

// 复合术语判定
Terms _compositeTerms(Board board, ChessStep chessStep,
    {List<ChessStep>? selfStepList,
    List<ChessStep>? oppositeStepList,
    int? distance}) {
  printInfo('进入复合术语判定');
  final int x = chessStep.y;
  final int y = 20 - chessStep.x;

  /// 计算两点之间的距离的平方
  int distanceSquared(int xx, int yy) =>
      (x - xx) * (x - xx) + (y - yy) * (y - yy);

  int s1 = 0; // 对方紧贴的棋子数
  int s2 = 0; // 对方斜斜的棋子数
  int s4 = 0; // 己方紧贴的棋子数
  int s5 = 0; // 己方斜斜的棋子数

  final grid = board.getChessBoard();
  final List<ChessStep> nonZeroSteps = [];

  // 获取所有非空棋子的坐标
  for (int i = 0; i < board.getBoardSize(); i++) {
    for (int j = 0; j < board.getBoardSize(); j++) {
      if (grid[i][j] != 0) {
        nonZeroSteps.add(ChessStep(j + 1, 20 - (i + 1), grid[i][j]));
      }
    }
  }

  ChessStep? coordinate1; // 对方的紧贴棋子
  // ChessStep? coordinate2; // 对方的斜斜棋子
  ChessStep? coordinate4; // 己方的紧贴棋子
  ChessStep? coordinate5; // 己方的斜斜棋子

  for (final step in nonZeroSteps) {
    final distance = distanceSquared(step.x, step.y);
    if (distance == 1) {
      if (step.bw != chessStep.bw) {
        s1++;
        coordinate1 = step;
      } else {
        s4++;
        coordinate4 = step;
      }
    } else if (distance == 2) {
      if (step.bw != chessStep.bw) {
        s2++;
        // coordinate2 = step;
      } else {
        s5++;
        coordinate5 = step;
      }
    }
  }

  printInfo('s1: $s1, s4: $s4, s5: $s5');

  if (s1 == 1 && s5 == 1) {
    if (s4 == 1) {
      if ((coordinate4!.y == coordinate5!.y &&
              coordinate1!.x == coordinate5.x) ||
          (coordinate4.x == coordinate5.x && coordinate1!.y == coordinate5.y)) {
        return Terms.TURN;
      } else if (coordinate4.y == y && coordinate1!.y == coordinate5.y) {
        return Terms.RESIST;
      }
    } else {
      if (coordinate1!.y == coordinate5!.y || coordinate1.x == coordinate5.x) {
        return Terms.HANE;
      } else {
        return Terms.KOSUMI_TOP;
      }
    }
  }
  // 1S2 * 1S4
  else if (s2 == 1 && s4 == 1) {
    return _directionAbstractTerms(s1, s4,
        nextStep: chessStep,
        board: board,
        selfStepList: selfStepList,
        distanceSquared: distance ?? 0,
        oppositeStepList: oppositeStepList);
  } else {
    return _directionAbstractTerms(s1, s4,
        nextStep: chessStep,
        board: board,
        selfStepList: selfStepList,
        distanceSquared: distance ?? 0,
        oppositeStepList: oppositeStepList);
  }

  return Terms.NONE;
}

bool isUnderFourQuadrant(TermsCoordinates? termsCoordinates) {
  if (termsCoordinates!.line == null) return false;
  String line = termsCoordinates.line!;
  return line == '一线' || line == '二线' || line == '三线';
}

// 并列术语判定
Terms _parataxisTerms(
    int count1, int count2, distanceSquared, ChessStep chessStep,
    {Board? board,
    List<ChessStep>? selfStepList,
    List<ChessStep>? oppositeStepList}) {
  printInfo('进入并列术语判定+$distanceSquared+count1:$count1+count2:$count2');
  var termsCoordinates = calculateDirection(chessStep.toGtp());
  // if (count1 == 1) {
  //   switch (distanceSquared) {
  //     // S3 镇
  //     case 1:
  //       return Terms.POKE;
  //     // 有疑问?
  //     case 2:
  //       return Terms.SHOULDER_HIT;
  //     // 栏
  //     case 4:
  //       return Terms.BLOCK;
  //   }
  // }
  // 颜色相同
  if (count2 > 0) {
    if (isUnderFourQuadrant(termsCoordinates)) {
      // 四线以内进入方位抽象判定
      return _directionAbstractTerms(count1, count2,
          distanceSquared: distanceSquared,
          selfStepList: selfStepList,
          oppositeStepList: oppositeStepList,
          nextStep: chessStep);
    } else {
      switch (distanceSquared) {
        // case 1:
        //   return Terms.STRETCH;
        // case 2:
        //   return Terms.KOSUMI;
        // S6 小跳
        case 4:
          return Terms.SMALL_JUMP;
        // S7 小飞
        case 5:
          return Terms.SMALL_FLY;
        // S8 象步
        case 8:
          return Terms.ELEPHANT_STEP;
        // S9 大跳
        case 9:
          return Terms.LARGE_JUMP;
        // S10 大飞
        case 10:
          return Terms.BIG_FLY;
        // S11 超⼤跳
        case 16:
          return Terms.SUPER_BIG_JUMP;
        // S12 超⼤飞
        case 17:
          return Terms.SUPER_BIG_FLY;
      }
    }
  }
  return Terms.NONE;
}

// 方位抽象判定
Terms _directionAbstractTerms(int oppositeCount, int selfCount,
    {int? distanceSquared,
    List<ChessStep>? selfStepList,
    List<ChessStep>? oppositeStepList,
    ChessStep? nextStep,
    Board? board}) {
  printInfo('进入方位抽象判定');
  printInfo(
      'selfCount:$selfCount+selfStepList:$selfStepList+oppositeCount:$oppositeCount+oppositeStepList:$oppositeStepList');

  var desc = calculateDirection(nextStep!.toGtp());
  int s1 = 0;
  int s4 = 0;
  if (distanceSquared == 1) {
    s1 = oppositeCount;
  }
  s4 = selfCount;

  if (s1 == 1) {
    if (s4 == 1) {
      ChessStep step1 = oppositeStepList![0];
      ChessStep step4 = selfStepList![0];
      if (desc!.direction == '⼀⼀') {
        return Terms.ONE_ONE_ENTER;
      } else if (desc.direction == '⼆⼆' ||
          desc.direction == '三三' ||
          desc.direction == '星位') {
        // 进⼊⽅向复合判定
        // return _directionAbstractTerms(s1, s4,
        //     selfStepList: selfStepList,
        //     oppositeStepList: oppositeStepList,
        //     nextStep: nextStep);
        return Terms.NONE;
      } else if (step1.y == step4.y || step1.x == step4.x) {
        return Terms.TOP;
      } else {
        int x = nextStep.y;
        int y = 20 - nextStep.x;
        // 满⾜相对于S4的上⽅向
        if (step4.x == x) {
          if (y == step4.y - 1) {
            return Terms.PRESS;
          }
          // 满⾜相对于S4的下⽅向
          else if (y == step4.y + 1) {
            return Terms.CLIMB;
          }
        } else {
          // 满⾜相对于S4的左、右⽅向
          if (step4.y == y) {
            if (x == step1.x) {
              // 满⾜相对于S1的上⽅向:贴
              if (y == step1.y - 1) {
                return Terms.ATTACH;
              }
              // 满⾜相对于S1的下⽅向:挡
              else if (y == step1.y + 1) {
                return Terms.RESIST;
              }
            }
          }
        }
      }
    } else if (s4 == 0) {
      // 特殊点,作为方向的分界线
      if (desc!.direction == '⼆⼆') {
        return Terms.TWO_TWO_HOLD;
      } else if (desc.direction == '三三') {
        return Terms.THREE_THREE_HOLD;
      } else if (desc.direction == '星位') {
        return Terms.STAR_DEPEND;
      } else {
        if (oppositeStepList!.length == 1) {
          var stepS1 = oppositeStepList[0];
          int x = nextStep.y;
          int y = 20 - nextStep.x;
          // 满⾜上⽅向
          if ((x == stepS1.x && y == stepS1.y - 1) ||
              y == stepS1.y && x == stepS1.x - 1) {
            if (desc.line == '四线') {
              return Terms.DEPEND;
            } else if (isUnderFourQuadrant(desc)) {
              return Terms.HOLD;
            }
          }
          // 满⾜下⽅向
          else if ((x == stepS1.x && y == stepS1.y + 1) ||
              (y == stepS1.y && x == stepS1.x + 1)) {
            // S1&S3\S6\S7\S8\S9\S10 靠
            if (distanceSquared! > 3 &&
                distanceSquared < 11 &&
                distanceSquared != 7) {
              return Terms.DEPEND;
            } else {
              return Terms.POKE;
            }
          }
          // 满⾜左、右⽅向
          else {
            return Terms.DEPEND;
          }
        }
      }
    }
    return Terms.NONE;
  }

  if (s4 == 1) {
    printInfo('进入特殊点判定');

    if (selfStepList!.isEmpty) {
      return Terms.NONE;
    }
    ChessStep step1 = selfStepList[0];
    ChessStep step2 = nextStep;

    bool isColorSame = step1.bw == step2.bw;

    int equal(String s1, String s2) {
      // step2是后手
      if (step1.toGtp() == s1 && step2.toGtp() == s2) {
        return 1;
      }
      // step2是先手
      else if (step1.toGtp() == s2 && step2.toGtp() == s1) {
        return -1;
      }
      return 0;
    }

    bool specialDot(List list, bool checkEqualToOne) {
      for (final pair in list) {
        final result = equal(pair[0], pair[1]);
        if (checkEqualToOne ? result == 1 : result == -1) {
          return true;
        }
      }
      return false;
    }

    printInfo('distanceSquared:$distanceSquared');
    // s6
    if (distanceSquared == 4) {
      if (isColorSame) {
        if (specialDot(s6Dots1, false)) {
          return Terms.SMALL_EYE_DG_ENCLOSURE;
        } else if (specialDot(s6Dots1, true)) {
          return Terms.SMALL_EYE_ENCLOSURE;
        } else if (specialDot(s6Dots2, false)) {
          return Terms.SMALL_EYE_DG_ENCLOSURE;
        } else if (specialDot(s6Dots2, true)) {
          return Terms.SMALL_EYE_ENCLOSURE;
        } else {
          Direction direction = isVertical(selfStepList, nextStep, distance: 2);
          // 满⾜上、下⽅向
          if (direction == Direction.UP || direction == Direction.DOWN) {
            return Terms.JUMP;
          } else {
            // 满⾜左、右⽅向
            return Terms.BREAK_ONE;
          }
        }
      } else {
        if (desc!.direction == '一一' || desc.direction == '二二') {
          return Terms.DOT;
        } else if (desc.direction == '三三') {
          return Terms.THREE_THREE_INVASION;
        } else {
          if (specialDot(s6Dots1, false)) {
            return Terms.SMALL_EYE_HIGH_INVASION;
          } else if (specialDot(s6Dots1, true)) {
            return Terms.SMALL_EYE_INVASION_CORNER;
          } else if (specialDot(s6Dots2, false)) {
            return Terms.STAR_HIGH_INVASION;
          } else if (specialDot(s6Dots2, true)) {
            return Terms.STAR_INVASION_CORNER;
          } else {
            Direction direction = isVertical(selfStepList, nextStep);
            //  满⾜上⽅向:镇
            if (direction == Direction.UP) {
              return Terms.POKE;
            }
            // 满⾜下⽅向:漏
            else if (direction == Direction.DOWN) {
              return Terms.LEAK;
            }
            // 满⾜左、右⽅向：栏
            else if (direction == Direction.HORIZONTAL) {
              return Terms.INTERCEPT;
            }
          }
        }
      }
    }
    // s7
    else if (distanceSquared == 5) {
      if (specialDot(s7Dots1, false)) {
        return Terms.MOYO_SHIMARI;
      } else if (specialDot(s7Dots1, true)) {
        return Terms.SMALL_EYE_ENCLOSURE;
      } else if (specialDot(s7Dots2, false)) {
        return Terms.SMALL_FLY_ENCLOSURE;
      } else if (specialDot(s7Dots2, true)) {
        return Terms.STAR_ENCLOSURE;
      } else {
        return Terms.SMALL_FLY;
      }
    } else if (distanceSquared == 9) {
      if (specialDot(s9Dots1, false)) {
        return Terms.BIG_JUMP_ENCLOSURE;
      } else if (specialDot(s9Dots1, true)) {
        return Terms.SMALL_EYE_ENCLOSURE;
      } else if (specialDot(s9Dots2, false)) {
        return Terms.STAR_BIG_JUMP_ENCLOSURE;
      } else if (specialDot(s9Dots2, true)) {
        return Terms.STAR_BREAK_TWO_ENCLOSURE;
      }
      Direction direction = isVertical(selfStepList, nextStep, distance: 3);
      // 满⾜上、下⽅向
      if (direction == Direction.UP || direction == Direction.DOWN) {
        return Terms.LARGE_JUMP;
      } else {
        // 满⾜左、右⽅向
        return Terms.BREAK_TWO;
      }
    } else if (distanceSquared == 10) {
      if (specialDot(s10Dots1, false)) {
        return Terms.BIG_JUMP_ENCLOSURE;
      } else if (specialDot(s10Dots1, true)) {
        return Terms.SMALL_EYE_ENCLOSURE;
      } else if (specialDot(s10Dots2, false)) {
        return Terms.BIG_FLY_ENCLOSURE;
      } else if (specialDot(s10Dots2, true)) {
        return Terms.STAR_ENCLOSURE;
      } else {
        return Terms.BIG_FLY;
      }
    }
    if (desc == null) {
      return Terms.NONE;
    }
  }
  return Terms.NONE;
}

/// 抽象判断
Terms judgeFromTrapezoid(Board board, ChessStep? nextStep) {
  int boardSize = board.getBoardSize();
  int x = nextStep!.y;
  int y = boardSize + 1 - nextStep.x;
  printInfo("x:$x,y:$y");

  int boardLimit = boardSize == 9 ? 3 : 4;

  if (y > boardSize - boardLimit && y < boardSize + 1) {
    if (x >= boardSize + 1 - y && x <= y) {}
  } else if (y > 0 && y < boardLimit + 1) {
    if (x >= y && x <= boardSize + 1 - y) {}
  } else if (x > 0 && x < boardLimit + 1) {
    if (y >= x && y <= boardSize + 1 - x) {}
  } else if (x > boardSize - boardLimit && x < boardSize + 1) {
    if (y >= boardSize + 1 - x && y <= x) {}
  }

  return Terms.NONE;
}
